﻿using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using pub.Functions;
using pub.Interop;
using pub.NET20Fix;

namespace todo
{
    public class WebBrowserEx : WebBrowser
    {
        #region enums

        public enum OLECMDID
        {
            OLECMDID_PRINT = 6,
            OLECMDID_PRINTPREVIEW = 7,
            OLECMDID_PAGESETUP = 8,
            // ...
            OLECMDID_OPTICAL_ZOOM = 63,
            OLECMDID_OPTICAL_GETZOOMRANGE = 64,
            // ...
        }

        public enum OLECMDEXECOPT
        {
            OLECMDEXECOPT_DODEFAULT,
            OLECMDEXECOPT_PROMPTUSER,
            OLECMDEXECOPT_DONTPROMPTUSER,
            OLECMDEXECOPT_SHOWHELP,
            // ...
        }

        public enum OLECMDF
        {
            // ...
            OLECMDF_SUPPORTED = 1
        }

        #endregion

        #region IWebBrowser2

        [ComImport, /*SuppressUnmanagedCodeSecurity,*/
         TypeLibType(TypeLibTypeFlags.FOleAutomation |
                     TypeLibTypeFlags.FDual |
                     TypeLibTypeFlags.FHidden),
         Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E")]
        public interface IWebBrowser2
        {
            [DispId(100)]
            void GoBack();

            [DispId(0x65)]
            void GoForward();

            [DispId(0x66)]
            void GoHome();

            [DispId(0x67)]
            void GoSearch();

            [DispId(0x68)]
            void Navigate([In] string Url,
                          [In] ref object flags,
                          [In] ref object targetFrameName,
                          [In] ref object postData,
                          [In] ref object headers);

            [DispId(-550)]
            void Refresh();

            [DispId(0x69)]
            void Refresh2([In] ref object level);

            [DispId(0x6a)]
            void Stop();

            [DispId(200)]
            object Application { [return:
                    MarshalAs(UnmanagedType.IDispatch)]
            get; }

            [DispId(0xc9)]
            object Parent { [return:
                    MarshalAs(UnmanagedType.IDispatch)]
            get; }

            [DispId(0xca)]
            object Container { [return:
                    MarshalAs(UnmanagedType.IDispatch)]
            get; }

            [DispId(0xcb)]
            object Document { [return:
                    MarshalAs(UnmanagedType.IDispatch)]
            get; }

            [DispId(0xcc)]
            bool TopLevelContainer { get; }

            [DispId(0xcd)]
            string Type { get; }

            [DispId(0xce)]
            int Left { get; set; }

            [DispId(0xcf)]
            int Top { get; set; }

            [DispId(0xd0)]
            int Width { get; set; }

            [DispId(0xd1)]
            int Height { get; set; }

            [DispId(210)]
            string LocationName { get; }

            [DispId(0xd3)]
            string LocationURL { get; }

            [DispId(0xd4)]
            bool Busy { get; }

            [DispId(300)]
            void Quit();

            [DispId(0x12d)]
            void ClientToWindow(out int pcx, out int pcy);

            [DispId(0x12e)]
            void PutProperty([In] string property,
                             [In] object vtValue);

            [DispId(0x12f)]
            object GetProperty([In] string property);

            [DispId(0)]
            string Name { get; }

            [DispId(-515)]
            int HWND { get; }

            [DispId(400)]
            string FullName { get; }

            [DispId(0x191)]
            string Path { get; }

            [DispId(0x192)]
            bool Visible { get; set; }

            [DispId(0x193)]
            bool StatusBar { get; set; }

            [DispId(0x194)]
            string StatusText { get; set; }

            [DispId(0x195)]
            int ToolBar { get; set; }

            [DispId(0x196)]
            bool MenuBar { get; set; }

            [DispId(0x197)]
            bool FullScreen { get; set; }

            [DispId(500)]
            void Navigate2([In] ref object URL,
                           [In] ref object flags,
                           [In] ref object targetFrameName,
                           [In] ref object postData,
                           [In] ref object headers);

            [DispId(0x1f5)]
            OLECMDF QueryStatusWB([In] OLECMDID cmdID);

            [DispId(0x1f6)]
            void ExecWB([In] OLECMDID cmdID,
                        [In] OLECMDEXECOPT cmdexecopt,
                        ref object pvaIn, IntPtr pvaOut);

            [DispId(0x1f7)]
            void ShowBrowserBar([In] ref object pvaClsid,
                                [In] ref object pvarShow,
                                [In] ref object pvarSize);

            [DispId(-525)]
            WebBrowserReadyState ReadyState { get; }

            [DispId(550)]
            bool Offline { get; set; }

            [DispId(0x227)]
            bool Silent { get; set; }

            [DispId(0x228)]
            bool RegisterAsBrowser { get; set; }

            [DispId(0x229)]
            bool RegisterAsDropTarget { get; set; }

            [DispId(0x22a)]
            bool TheaterMode { get; set; }

            [DispId(0x22b)]
            bool AddressBar { get; set; }

            [DispId(0x22c)]
            bool Resizable { get; set; }
        }

        #endregion

        private IWebBrowser2 axIWebBrowser2;
        private int _zoom;

        private bool _defaultPageSetupChanged;
        private object _footer;
        private object _header;


        public WebBrowserEx()
        {
            _zoom = 100;
        }

        protected override void AttachInterfaces(
                object nativeActiveXObject)
        {
            if (this.DesignMode)
            {
                base.AttachInterfaces(nativeActiveXObject);
                return;
            }
            base.AttachInterfaces(nativeActiveXObject);
            this.axIWebBrowser2 = (IWebBrowser2) nativeActiveXObject;
        }

        protected override void DetachInterfaces()
        {
            if (this.DesignMode)
            {
                base.DetachInterfaces();
                return;
            }
            base.DetachInterfaces();
            this.axIWebBrowser2 = null;
        }

        public int Zoom
        {
            get { return _zoom; }
            set
            {
                if (this.DesignMode)
                {
                    return;
                }
                if (this.Document == null)
                {
                    return;
                }
                _zoom = value;
                object pvaIn = value;
                try
                {
                    this.axIWebBrowser2.ExecWB(OLECMDID.OLECMDID_OPTICAL_ZOOM,
                            OLECMDEXECOPT.OLECMDEXECOPT_DONTPROMPTUSER,
                            ref pvaIn, IntPtr.Zero);
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }


        //
        public new void ShowPrintPreviewDialog()
        {
            SetHeaderFooterThenExec(() => {
                var pvaIn = (object) null;
                this.axIWebBrowser2.ExecWB(OLECMDID.OLECMDID_PRINTPREVIEW,
                        OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER, ref pvaIn, IntPtr.Zero);
            });
        }

        public new void ShowPrintDialog()
        {
            SetHeaderFooterThenExec(() => {
                object arrObj = null;
                this.axIWebBrowser2.ExecWB(OLECMDID.OLECMDID_PRINT,
                        OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER,
                        ref arrObj, IntPtr.Zero);
            });
        }

        public new void ShowPageSetupDialog()
        {
            ((WebBrowser) this).ShowPageSetupDialog();
//            SetHeaderFooterThenExec(() => ((WebBrowser)this).ShowPageSetupDialog());
        }

        private void SetHeaderFooterThenExec(Action action)
        {
            RegistryKey key;
            var keyName = @"Software\Microsoft\Internet Explorer\PageSetup";

            if (!_defaultPageSetupChanged)
            {
                key = Registry.CurrentUser.OpenSubKey(keyName);
                _footer = key.GetValue("footer");
                _header = key.GetValue("header");
                key.Close();
            }

            key = Registry.CurrentUser.OpenSubKey(keyName, true);
            var fileName = PathFuncs.CompactPath(App.TodoListFile, 60);
            key.SetValue("footer", fileName + "&b&d");
            var footerRight = "Page &p of &P";
#if zh
            footerRight = "第 &p/&P 页";
#endif
            key.SetValue("header", App.TodoList.Title + "&b" + footerRight);
            key.Close();

            _defaultPageSetupChanged = true;

            //Win32.PostMessage(App.MainForm.Handle, App.MainForm.)
            var mainFormHwnd = App.MainForm.Handle;
            new Thread(() => {
                while (Win32.GetForegroundWindow() == mainFormHwnd)
                {
                    Thread.Sleep(10);
                }
                Thread.Sleep(500);
                CheckRestoreDefaultPageSetup();
            }).Start();

            action();
        }

        public void CheckRestoreDefaultPageSetup()
        {
            if (!_defaultPageSetupChanged)
            {
                return;
            }
            var keyName = @"Software\Microsoft\Internet Explorer\PageSetup";
            var key = Registry.CurrentUser.OpenSubKey(keyName, true);
            if (_footer == null)
            {
                key.DeleteValue("footer");
            }
            else
            {
                key.SetValue("footer", _footer);
            }
            if (_header == null)
            {
                key.DeleteValue("header");
            }
            else
            {
                key.SetValue("header", _header);
            }
            key.Close();
            _defaultPageSetupChanged = false;
        }
    }
}